package com.geek.water.controller;


import cn.hutool.json.JSONUtil;
import com.geek.water.constant.CodeConstant;
import com.geek.water.constant.MessageConstant;
import com.geek.water.constant.RedisTokenConstant;
import com.geek.water.entity.User;
import com.geek.water.exception.HealthException;
import com.geek.water.exception.RefreshTokenInvalidException;
import com.geek.water.result.Result;
import com.geek.water.security.LoginUser;
import com.geek.water.service.UserService;
import com.geek.water.utils.JwtHelper;
import com.geek.water.vo.UserLoginQueryVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * @author chenmin
 * @desc 认证
 * @date 2025/7/24
 *  * http://localhost:8080/swagger-ui.html
 *  * http://localhost:8080/doc.html
 */
@RestController
@RequestMapping("/admin/auth")
@Slf4j
@Api(tags = "后台系统-认证接口")
@RequiredArgsConstructor
public class AuthController {
    private final UserService userService;
    private final AuthenticationManager authenticationManager;
    private final RedisTemplate<String,Object> redisTemplate;

    @ApiOperation("登录")
    @PostMapping("login")
    public Result login(@RequestBody UserLoginQueryVO vo){
        //TODO 基于Security + JWT 实现登录认证
        String username = vo.getUsername();
        String password = vo.getPassword();
        if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
            return new Result(CodeConstant.FAIL , MessageConstant.LOGIN_FAIL);
        }

        //1.创建基于姓名和密码的认证管理
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username , password);
        //2.调用自定义的UserDetailsService中的loadUserByUsername()
        Authentication authenticate = authenticationManager.authenticate(authentication);
        if(ObjectUtils.isEmpty(authenticate)){
            //认证不通过
            throw new HealthException(MessageConstant.LOGIN_FAIL);
        }
        //3.认证通过
        LoginUser loginUser = (LoginUser)authenticate.getPrincipal();
        if(loginUser!=null){
            User user = loginUser.getUser();

            //4.姓名和密码匹配时，生成token令牌
            //生成访问Token令牌
            String accessToken = JwtHelper.createToken(user.getId().longValue(), user.getUsername());
            //生成刷新Token令牌
            String refreshToken = JwtHelper.refreshToken(accessToken);
            Map<String, Object> map = new HashMap<>();
            map.put("accessToken", accessToken);
            map.put("refreshToken", refreshToken);

            //5.将认证信息存储至Redis中
            redisTemplate.opsForValue().set(RedisTokenConstant.USER_TOKEN + "::" + user.getId() , JSONUtil.toJsonStr(user));

            //6.响应token信息
            return new Result(CodeConstant.SUCCESS , MessageConstant.LOGIN_SUCCESS, map);
        }
        return new Result(CodeConstant.FAIL , MessageConstant.LOGIN_FAIL);

        /*//1.通过姓名和密码查询用户信息
        User user = userService.login(vo);
        if(!ObjectUtils.isEmpty(user)){
            //2.姓名和密码匹配时，生成token令牌
            //生成访问Token令牌
            String accessToken = JwtHelper.createToken(user.getId().longValue(), user.getUsername());
            //生成刷新Token令牌
            String refreshToken = JwtHelper.refreshToken(accessToken);
            Map<String, Object> map = new HashMap<>();
            map.put("accessToken", accessToken);
            map.put("refreshToken", refreshToken);
            //3.响应token信息
            return new Result(CodeConstant.SUCCESS , MessageConstant.LOGIN_SUCCESS, map);
        }
        return new Result(CodeConstant.FAIL , MessageConstant.LOGIN_FAIL);*/
    }

    @ApiOperation("刷新令牌")
    @PostMapping("refreshToken")
    public Result refreshToken(String refreshToken){
        if(!StringUtils.hasLength(refreshToken) || JwtHelper.isExpiration(refreshToken)){
            throw new RefreshTokenInvalidException(MessageConstant.REFRESH_TOKEN_VERIFY_FAIL);
        }

        //获取刷新令牌中的登录信息
        Long userId = JwtHelper.getUserId(refreshToken);
        String userName = JwtHelper.getUserName(refreshToken);
        //重新生成访问accessToken令牌
        String accessToken = JwtHelper.createToken(userId, userName);
        Map<String, Object> map = new HashMap<>();
        map.put("accessToken", accessToken);
        map.put("refreshToken", refreshToken);
        //3.响应token信息
        return new Result(CodeConstant.SUCCESS , MessageConstant.TOKEN_REFRESH, map);
    }

    @ApiOperation("登出")
    @GetMapping("logout")
    public Result logout(){
        //TODO 基于Security实现登出
        //从认证上下文SecurityContextHolder中，取出认证通过的信息Authentication（用户信息、权限、以认证状态等）
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser)authentication.getPrincipal();
        if(!ObjectUtils.isEmpty(loginUser)){
            Integer id = Math.toIntExact(loginUser.getUser().getId());
            Boolean flag = redisTemplate.delete(RedisTokenConstant.USER_TOKEN + "::" + id);
            if(flag){
                return new Result(CodeConstant.SUCCESS , MessageConstant.LOGOUT_SUCCESS);
            }
        }
        return new Result(CodeConstant.FAIL , MessageConstant.LOGOUT_FAIL);
    }
}

